﻿/*
* Slickflow 工作流引擎遵循LGPL协议，也可联系作者商业授权并获取技术支持；
* 除此之外的使用则视为不正当使用，请您务必避免由此带来的商业版权纠纷。

The Slickflow Designer project.
Copyright (C) 2014  .NET Workflow Engine Library

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, you can access the official
web page about lgpl: https://www.gnu.org/licenses/lgpl.html
*/

var kmain = (function () {
    function kmain() {
    }

    kmain.init = function (mode) {
        //waiting...
        showProgressBar();

        $("#kgraphCanvas").on("click", function (e) {
            $(this).focus();
        })

        //fix two modal dialog in IE9 to IE11
        $.fn.modal.Constructor.prototype.enforceFocus = function () { };

        //register process opened event
        if ("undefined" !== typeof processlist) {
            processlist.afterCreated.subscribe(afterProcessCreated);
            processlist.afterOpened.subscribe(afterProcessOpened);
        }
    }

    kmain.showDiagramReadOnly = function () {
        //the process graph is readonly for business process veiwer,
        //when it needed from applicaiton page.
        kmain.mxGraphEditor = createEditor('/scripts/mxGraph/config/workfloweditor-readonly.xml');
    }

    function initializeGlobalVariables() {
        kmain.mxSelectedProcessEntity = null;
        kmain.mxSelectedDomElement = {};
        kmain.mxSelectedPackageData = null;
        kmain.mxSelectedParticipants = [];
    }

    //intialize workflow editor
    kmain.initializeMxGraphEditor = function () {
        var keditor = kmain.mxGraphEditor = createEditor('/Scripts/mxgraph/config/workfloweditor.xml');
        var kgraph = kmain.mxGraphEditor.graph;

        keditor.addListener(mxEvent.SAVE, function () {
            kmain.saveProcessFile();
        });
        kgraph.addListener(mxEvent.CELLS_ADDED, function (cell) {
            //window.console.log(cell.getValue());
            /*
            $.msgBox({
				title: "Designer / Index",
				content: "图形节点添加事件触发！",
				type: "info"
			});*/
            //mxUtils.error('节点添加事件！', 200, false);
        });
        kgraph.addMouseListener({
            mouseDown: function (sender, evt) {
                //window.console.log('mouseDown');
            },
            mouseMove: function (sender, evt) {
            },
            mouseUp: function (sender, evt) {
            }
        });
        kgraph.connectionHandler.addListener(mxEvent.CONNECT, function (sender, evt) {
            //var edge = evt.getProperty('cell');
            //var style = kgraph.getCellStyle(edge); //style is in object form
            //var newStyle = kgraph.stylesheet.getCellStyle("edgeStyle=orthogonalEdgeStyle;html=1;rounded=1;jettySize=auto;orthogonalLoop=1;strokeColor=#2d8e3d;strokeWidth=2;", style); //Method will merge styles into a new style object.  We must translate to string from here 
            //var array = [];
            //for (var prop in newStyle)
            //    array.push(prop + "=" + newStyle[prop]);
            //edge.style = array.join(';');
        });
        keditor.createProperties = function (cell) {
            var model = this.graph.getModel();
            var snode = model.getValue(cell);

            if (mxUtils.isNode(snode)) {
                kmain.mxSelectedDomElement.Cell = cell;

                if (model.isVertex(cell)) {
                    if (snode.nodeName === "Activity") {
                        kmain.mxSelectedDomElement.ElementType = 'Activity';
                        var activity = kmain.mxSelectedDomElement.Element = convert2ActivityObject(cell);
                        showActivityPropertyDialog(activity);
                    } else if (snode.nodeName === "Swimlane") {
                        ;
                    }
                } else if (model.isEdge(cell)) {
                    if (snode.nodeName === "Transition") {
                        //transition page
                        kmain.mxSelectedDomElement.ElementType = 'Transition';
                        var transition = kmain.mxSelectedDomElement.Element = convert2TransitionObject(cell);
                        //BootstrapDialog.show({
                        // title: '转移属性',
                        //             message: $('<div></div>').load('/platform/transition/edit'),
                        //             data: { "node": transition },
                        //             draggable: true
                        //         });

                        //Ext.net.directRequest({
                        //    cleanRequest: true,
                        //    url: '/platform/transition/edit',
                        //    extraParams: transition,
                        //    method: "POST",
                        //    control: this,
                        //    eventMask: {
                        //        showMask: true,
                        //        msg: "正在打开..."
                        //    }
                        //});

                        Ext.create("Ext.window.Window", {
                            title: "转移属性编辑", width: 500, height: 300, layout: "fit", autoShow: true,
                            items: [
                                {
                                    xtype: "form",
                                    fieldDefaults: {
                                        labelWidth: 110,
                                        labelAlign: "right",
                                        labelSeparator: "：",
                                        padding: 4
                                    },
                                    items: [
                                        { xtype: "textfield", name: "Description", fieldLabel: "描述", allowBlank: false, value: transition.description },
                                        {
                                            xtype: "combobox", name: "ReceiverType", fieldLabel: "接收者类型",
                                            store: Ext.create("Ext.data.Store", {
                                                fields: ["Name", "Value"],
                                                data: [{ Name: "请选择", Value: "default" },
                                                { Name: "上司", Value: "Superior" },
                                                { Name: "同事", Value: "Compeer" },
                                                { Name: "下属", Value: "Subordinate" }
                                                ]
                                            }),
                                            editable: false,
                                            displayField: "Name",
                                            valueField: "Value",
                                            emptyText: "--请选择--",
                                            queryMode: "local", value: transition.receiver.type
                                        },
                                        { xtype: "textfield", name: "Condition", fieldLabel: "条件表达式", allowBlank: false, value: transition.condition.text }
                                    ]
                                }
                            ],
                            buttons: [
                                { xtype: "button", text: "确定", handler: function () { transitionproperty.save(this.up("window").down("form").getForm()); } },
                                { xtype: "button", text: "取消", handler: function () { this.up("window").close(); } }
                            ]
                        });
                    }
                }
            }
        }

        keditor.showAdvanced = function (cell) {
            window.console.log("show advanced...in kmain");
        }
    }

    function showActivityPropertyDialog(activity) {
        if (activity.type === kmodel.Config.NODE_TYPE_TASK
            || activity.type === kmodel.Config.NODE_TYPE_MULTIPLEINSTANCE) {
            BootstrapDialog.show({
                title: '活动属性',
                message: $('<div></div>').load('/workflow/activity/edit'),
                data: { "node": activity },
                draggable: true
            });
        } else if (activity.type === kmodel.Config.NODE_TYPE_GATEWAY) {
            //BootstrapDialog.show({
            // title: '网关决策属性',
            //       message: $('<div></div>').load('/workflow/activity/gateway'),
            //       data: { "node": activity },
            //       draggable: true
            //});

            var transition = kmain.mxSelectedDomElement.Element;
            Ext.create("Ext.window.Window", {
                title: "转移属性编辑", width: 500, height: 300, layout: "fit", autoShow: true,
                items: [
                    {
                        xtype: "form",
                        fieldDefaults: {
                            labelWidth: 110,
                            labelAlign: "right",
                            labelSeparator: "：",
                            padding: 4
                        },
                        items: [
                            {
                                xtype: "combobox", name: "GatewayType", fieldLabel: "类型",
                                store: Ext.create("Ext.data.Store", {
                                    fields: ["Name", "Value"],
                                    data: [{ Name: "请选择", Value: "default" }, { Name: "分支", Value: "Split" }, { Name: "合并", Value: "Join" }
                                    ]
                                }),
                                editable: false,
                                displayField: "Name",
                                valueField: "Value",
                                emptyText: "--请选择--",
                                queryMode: "local", value: transition.gatewaySplitJoinType
                            },
                            {
                                xtype: "combobox", name: "DirectionType", fieldLabel: "子类型",
                                store: Ext.create("Ext.data.Store", {
                                    fields: ["Name", "Value"],
                                    data: [{ Name: "请选择", Value: "default" }
                                    ]
                                }),
                                editable: false,
                                displayField: "Name",
                                valueField: "Value",
                                emptyText: "--请选择--",
                                queryMode: "local", value: transition.gatewayDirection
                            },
                            { xtype: "textfield", name: "Description", fieldLabel: "描述", allowBlank: false, value: transition.description }
                        ]
                    }
                ],
                buttons: [
                    { xtype: "button", text: "确定", handler: function () { transitionproperty.save(this.up("window").down("form").getForm()); } },
                    { xtype: "button", text: "取消", handler: function () { this.up("window").close(); } }
                ]
            });


        } else if (activity.type === kmodel.Config.NODE_TYPE_SUBPROCESS) {
            BootstrapDialog.show({
                title: '子流程属性',
                message: $('<div></div>').load('/workflow/activity/subprocess'),
                data: { "node": activity },
                draggable: true
            });
        } else if (activity.type === kmodel.Config.NODE_TYPE_START
            || activity.type === kmodel.Config.NODE_TYPE_END) {
            ;
        }
        else {
            $.msgBox({
                title: "Designer / Property",
                content: "未知节点类型！" + activity.type,
                type: "alert"
            });
            return false;
        }
    }

    function convert2ActivityObject(cell) {
        var model = kmain.mxGraphEditor.graph.getModel();
        var snode = model.getValue(cell);

        //activity
        var activity = mxfile.getActivityObject(snode, "label");

        //description
        var descriptionElement = snode.getElementsByTagName("Description")[0];
        if (descriptionElement) activity.description = descriptionElement.textContent;

        //activity type
        var activityTypeElement = snode.getElementsByTagName("ActivityType")[0];
        activity = mxfile.getActivityTypeObject(activity, activityTypeElement);

        //performers
        var performersElement = snode.getElementsByTagName("Performers")[0];
        if (performersElement) {
            var performers = [];
            Array.prototype.forEach.call(performersElement.getElementsByTagName("Performer"), function (performerElement) {
                var performer = mxfile.getPerformerObject(performerElement);
                performers.push(performer);
            });
            activity.performers = performers;
        }

        //actions
        var actionsElement = snode.getElementsByTagName("Actions")[0];
        if (actionsElement) {
            var actions = [];
            Array.prototype.forEach.call(actionsElement.getElementsByTagName("Action"), function (actionElement) {
                var action = mxfile.getActionObject(actionElement);
                actions.push(action);
            });
            activity.actions = actions;
        }
        return activity;
    }

    function convert2TransitionObject(cell) {
        var model = kmain.mxGraphEditor.graph.getModel();
        var sline = model.getValue(cell);

        var transition = mxfile.getTransitionObject(sline);

        var descriptionElement = sline.getElementsByTagName("Description")[0];
        if (descriptionElement) transition.description = descriptionElement.textContent;

        var conditionElement = sline.getElementsByTagName("Condition")[0];
        if (conditionElement) transition.condition = mxfile.getConditionObject(conditionElement);

        var receiverElement = sline.getElementsByTagName("Receiver")[0];
        transition.receiver = mxfile.getReceiverObject(receiverElement);

        return transition;
    }

    function createEditor(config) {
        var editor = null;
        try {
            if (!mxClient.isBrowserSupported()) {

                Tip("Designer / Index", "不支持当前版本的浏览器，请使用更新版本的浏览器！");
            } else {
                mxObjectCodec.allowEval = true;
                var node = mxUtils.load(config).getDocumentElement();

                editor = new mxEditor(node);
                mxObjectCodec.allowEval = false;
                editor.graph.createPanningManager = function () {
                    var pm = new mxPanningManager(this);
                    pm.border = 30;
                    return pm;
                };
                editor.graph.allowAutoPanning = true;
                editor.graph.timerAutoScroll = true;

                var title = document.title;
                var funct = function (sender) {
                    if (sender.getTitle() != "undefined") {
                        document.title = title + ' - ' + sender.getTitle();
                    }
                };
                editor.addListener(mxEvent.OPEN, funct);
                editor.addListener(mxEvent.ROOT, funct);
                funct(editor);
                editor.setStatus('mxGraph ' + mxClient.VERSION);
            }
        } catch (e) {
            $.msgBox({
                title: "Designer / Index",
                content: "图形设计器启动异常：" + e.message,
                type: "info"
            });
            throw e;
        }
        return editor;
    }
    //#endregion

    //#region toolbar action in home page
    kmain.createProcess = function () {
        //clear canvas
        kmain.mxGraphEditor.graph.getModel().clear();
        //create process
        processlist.createProcess();

        return false;
    }

    kmain.openProcess = function () {
        //BootstrapDialog.show({
        //	title: '流程列表',
        //          message: $('<div></div>').load('/Workflow/process/list'),
        //          draggable: true
        //      });
        //      return false;
    }

    kmain.setting = function () {
        BootstrapDialog.show({
            title: '系统参数设置',
            message: $("<div>你可以在这个页面设置一些参数。。。</div>"),
            buttons: [{
                label: '确定',
                cssClass: 'btn-primary',
                action: function (dialogItself) {
                    dialogItself.close();
                }
            }]
        });
    }

    kmain.previewXml = function () {
        var xmlContent = kloader.serialize2Xml(kmain.mxSelectedProcessEntity,
            kmain.mxSelectedParticipants);

        if ($.isEmptyObject(xmlContent) === false) {
            Ext.create("Ext.window.Window", {
                title: "XML文件内容",
                width: 700,
                height: 440,
                layout: "fit",
                autoShow: true,
                items: [{ xtype: "textareafield", name: "name", value: xmlContent, allowBlank: false }]
            });
        } else {
            Tip("图形内容为空，请确认是否打开流程记录！");
            return;
        }
    }
    kmain.importDiagram = function () {
        Ext.create("Ext.window.Window", {
            title: "XML文件内容",
            width: 700,
            height: 440,
            layout: "fit",
            autoShow: true,
            items: [{ xtype: "textareafield", name: "name", value: "", allowBlank: false }],
            buttons: [{
                text: '保存', handler: function () {
                    var xmlContent = this.up("window").down("textareafield").getValue();

                    var query = {
                        "ID": processID
                    };
                    processapi.queryProcessFileByID(query,
                        function (res) {

                            kmain.mxGraphEditor.graph.getModel().clear();
                            res.xmlContent = xmlContent;
                            res.entity.xmlContent = xmlContent;
                            kloader.load(res);

                            processapi.saveProcessFile(res.entity);
                        });
                    this.up("window").close();
                }
            }, {
                text: '关闭', handler: function () { this.up("window").close(); }
            }]
        });
    }

    function afterProcessCreated(e, data) {
        //intialize process variables
        initializeGlobalVariables();
        //get mxEditor graph xml
        kmain.mxSelectedProcessEntity = data.ProcessEntity;
        //save process file
        kmain.saveProcessFile();
    }

    kmain.saveProcessFile = function () {
        if (kmain.mxSelectedProcessEntity) {
            var xmlContent = kloader.serialize2Xml(kmain.mxSelectedProcessEntity,
                kmain.mxSelectedParticipants);
            var entity = {
                "ProcessGUID": kmain.mxSelectedProcessEntity.processGUID,
                "Version": kmain.mxSelectedProcessEntity.version,
                "XmlContent": xmlContent
            };
            processapi.saveProcessFile(entity);
        } else {
            processlist.createProcess();
        }

        return false;
    }

    function afterProcessOpened(e, data) {
        //intialize process variables
        initializeGlobalVariables();

        var query = {
            "ProcessGUID": data.ProcessEntity.processGUID,
            "Version": data.ProcessEntity.version
        };

        processapi.queryProcessFile(query, function (result) {
            if (result.errors.length === 0) {
                //clear graph canvas
                kmain.mxGraphEditor.graph.getModel().clear();
                //inialize graph canvas
                var graphData = kloader.load(result.data);
                kmain.mxSelectedPackageData = graphData.package;
                kmain.mxSelectedParticipants = graphData.package.participants;
                kmain.mxSelectedProcessEntity = data.ProcessEntity;
            } else {
                $.msgBox({
                    title: "Designer / Process",
                    content: "流程定义记录读取失败！错误：" + result.message,
                    type: "error"
                });
            }
        });
    }

    //xml of mxGraphEditor
    function previewMxGraphXMLContent() {
        var model = kmain.mxGraphEditor.graph.getModel();
        var encoder = new mxCodec();
        var mxGraphModelData = encoder.encode(model);
        var graphXmlContent = mxUtils.getPrettyXml(mxGraphModelData);

        return graphXmlContent;
    }
    //#endregion

    //#region set vertex and edut value
    kmain.setVertexValue = function (activity) {
        var model = kmain.mxGraphEditor.graph.getModel();
        var snode = model.getValue(kmain.mxSelectedDomElement.Cell);

        snode.setAttribute('label', activity.name);
        snode.setAttribute('code', activity.code);

        var descriptionElement = snode.getElementsByTagName("Description")[0];
        if (!descriptionElement) {
            descriptionElement = snode.appendChild(snode.ownerDocument.createElement('Description'));
        }
        descriptionElement.textContent = activity.description;

        //activity type
        var activityTypeElement = snode.getElementsByTagName("ActivityType")[0];
        activityTypeElement = mxfile.setActivityTypeElement(activityTypeElement, activity);

        model.beginUpdate();
        try {
            model.setValue(kmain.mxSelectedDomElement.Cell, snode);
        } finally {
            model.endUpdate();
        }
    }

    kmain.setVertexPerformers = function (performers) {
        var model = kmain.mxGraphEditor.graph.getModel();
        var snode = model.getValue(kmain.mxSelectedDomElement.Cell);

        if (performers) {
            var performersElement = snode.getElementsByTagName("Performers")[0];
            if (!performersElement) {
                performersElement = snode.appendChild(snode.ownerDocument.createElement("Performers"));
            } else {
                removeChildren(performersElement);
            }

            var performer = null,
                performerElement = null;
            for (var i = 0; i < performers.length; i++) {
                performer = performers[i];
                performerElement = mxfile.setPerformerElement(performersElement.ownerDocument, performer);
                performersElement.appendChild(performerElement);
            }
        }

        model.beginUpdate();
        try {
            model.setValue(kmain.mxSelectedDomElement.Cell, snode);
        } finally {
            model.endUpdate();
        }
    }

    var removeChildren = function (node) {
        var last;
        while (last = node.lastChild) node.removeChild(last);
    };

    kmain.setEdgeValue = function (transition) {
        var model = kmain.mxGraphEditor.graph.getModel();
        var sline = model.getValue(kmain.mxSelectedDomElement.Cell);

        var descriptionElement = sline.getElementsByTagName("Description")[0];
        if (!descriptionElement) {
            descriptionElement = sline.appendChild(sline.ownerDocument.createElement('Description'));
        }
        descriptionElement.textContent = transition.description;

        sline.setAttribute('label', transition.description);
        sline.setAttribute('from', transition.from);
        sline.setAttribute('to', transition.to);

        if (transition.condition) {
            var conditionElement = sline.getElementsByTagName("Condition")[0];
            if (!conditionElement) {
                conditionElement = sline.appendChild(sline.ownerDocument.createElement('Condition'));
            }
            conditionElement.setAttribute('type', transition.condition.type);
            var conditionTextElement = conditionElement.getElementsByTagName("ConditionText")[0];
            if (!conditionTextElement) {
                conditionTextElement = conditionElement.appendChild(sline.ownerDocument.createElement('ConditionText'));
            }
            conditionTextElement.textContent = transition.condition.text;
        }

        var receiverElement = sline.getElementsByTagName("Receiver")[0];
        if (!receiverElement) {
            receiverElement = sline.appendChild(sline.ownerDocument.createElement('Receiver'));
        }
        receiverElement.setAttribute("type", transition.receiver.type);

        model.beginUpdate();
        try {
            model.setValue(kmain.mxSelectedDomElement.Cell, sline);
        } finally {
            model.endUpdate();
        }
    }
    //#endregion

    //#region preparation
    function showProgressBar() {
        //$('.progress .progress-bar').progressbar({
        //	transition_delay: 200
        //});

        //var $modal = $('.js-loading-bar'),
        //          $bar = $modal.find('.bar');

        //$modal.modal('show');

        //setTimeout(function () {
        //	$modal.modal('hide');
        //}, 500);
    }
    //#endregion

    //#region render process diagram for application project
    //render ready activity nodes in kgraph canvas
    kmain.renderReadyTasks = function (activityList) {
        var graph = kmain.mxGraphEditor.graph;
        var model = kmain.mxGraphEditor.graph.getModel();
        model.beginUpdate();
        try {
            $.each(activityList, function (idx, activity) {
                var cell = model.getCell(activity.ActivityGUID);
                cell.setStyle("strokeColor=green;fillColor=green;");    //change ready task color to green
                graph.refresh();
            })
        } finally {
            model.endUpdate();
        }
    }

    //render transition red color for completed transitons
    kmain.renderCompletedTransitions = function (transitionList) {
        var graph = kmain.mxGraphEditor.graph;
        var model = kmain.mxGraphEditor.graph.getModel();
        model.beginUpdate();
        try {
            $.each(transitionList, function (idx, transition) {
                var edge = model.getCell(transition.TransitionGUID);
                if (edge !== undefined) {
                    var style = graph.getCellStyle(edge); //style is in object form
                    var newStyle = graph.stylesheet.getCellStyle("edgeStyle=orthogonalEdgeStyle;html=1;rounded=1;jettySize=auto;orthogonalLoop=1;strokeColor=red;strokeWidth=2;", style); //Method will merge styles into a new style object.  We must translate to string from here 
                    var array = [];
                    for (var prop in newStyle)
                        array.push(prop + "=" + newStyle[prop]);
                    edge.style = array.join(';');

                    graph.refresh();
                }
            });
        } finally {
            model.endUpdate();
        }
    }
    //#endregion
    return kmain;
})()